/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Aardvark.
 *
 * The Initial Developer of the Original Code is Rob Brown.
 * Portions created by the Initial Developer are Copyright (C) 2005-2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Jiří Mašek
 *
 * ***** END LICENSE BLOCK ***** */

/**********************************
 * aardvarkExtension.js *
 **********************************/

// create the main aardvark object
var aardvark = {
resourcePrefix:"chrome://aardvark/content/",
strings : {
	initialTipText : '',
	viewHtmlSource : '',
	javascriptDomCode : '',
	aardvarkKeystrokes : '',
	karmaticsPlug : '',
	ripHelp : '',
	wider : '',
	narrower : '',
	undo : '',
	quit : '',
	remove : '',
	kill : '',
	isolate : '',
	blackOnWhite : '',
	deWidthify : '',
	colorize : '',
	viewSource : '',
	javascript : '',
	paste : '',
	help : ''
	}
};

/**********************************
 * aardvarkUtils.js *
 **********************************/

//-----------------------------------------------------
aardvark.setElementStyleDefault = function(elem, bgColor) {
var s = elem.style;
s.display = "none";
s.backgroundColor = bgColor;
s.borderColor = "black";
s.borderWidth = "1px 2px 2px 1px";
s.borderStyle = "solid";
s.fontFamily = "arial";
s.textAlign = "left";
s.color = "#000";
s.fontSize = "12px";
s.position = "absolute";
s.paddingTop = "2px";
s.paddingBottom = "2px";
s.paddingLeft = "5px";
s.paddingRight = "5px";
}

//-----------------------------------------------------
aardvark.getPos = function (o) {
var pos = {};

var leftX = 0;
var leftY = 0;
if (o.offsetParent) {
	while (o.offsetParent) {
		leftX += o.offsetLeft;
		leftY += o.offsetTop;
		o = o.offsetParent;
		}
	}
else if (o.x) {
	leftX += o.x;
	leftY += o.y;
	}
pos.x = leftX;
pos.y = leftY;
return pos;
};

aardvark.setAardvarkElem = function (elem) {
if (elem.nodeType == 1) { // ELEMENT_NODE
	for (var i=0; i<elem.childNodes.length; i++) {
		elem.isAardvark = true;
		aardvark.setAardvarkElem(elem.childNodes.item(i));
		}
	}
};

//-----------------------------------------------------
aardvark.setHandler = function(obj, eventName, code) {
if (aardvark.doc.all)
	obj.attachEvent ("on" + eventName, code);
else
	obj.addEventListener (eventName, code, false);
};

//-----------------------------------------------------
// move a div (or whatever) to an x y location
aardvark.moveElem = function (o, x, y) {
o = o.style;

if (aardvark.doc.all) {
	o.pixelLeft=x;
	o.pixelTop=y;
	}
else {
	o.left=x + "px";
	o.top=y + "px";
	}
};

//-------------------------------------------------
aardvark.getElemFromEvent = function (evt) {
return ((evt.target) ? evt.target : evt.srcElement);
}

//-------------------------------------------------
aardvark.getWindowDimensions = function () {
var out = {};

if (aardvark.window.pageXOffset) {
	out.scrollX = aardvark.window.pageXOffset;
	out.scrollY = aardvark.window.pageYOffset;
	}
else if (aardvark.doc.documentElement) {
	out.scrollX = aardvark.doc.body.scrollLeft +
				aardvark.doc.documentElement.scrollLeft;
	out.scrollY = aardvark.doc.body.scrollTop +
				aardvark.doc.documentElement.scrollTop;
	}
else if (aardvark.doc.body.scrollLeft >= 0) {
	out.scrollX = aardvark.doc.body.scrollLeft;
	out.scrollY = aardvark.doc.body.scrollTop;
	}
if (aardvark.doc.compatMode == "BackCompat") {
	out.width = aardvark.doc.body.clientWidth;
	out.height = aardvark.doc.body.clientHeight;
	}
else {
	out.width = aardvark.doc.documentElement.clientWidth;
	out.height = aardvark.doc.documentElement.clientHeight;
	}
return out;
}

aardvark.leafElems = {IMG:true, HR:true, BR:true, INPUT:true};

//--------------------------------------------------------
// generate "outerHTML" for an element
// this doesn't work on IE, but its got its own outerHTML property
aardvark.getOuterHtml = function (node) {
var str = "";

switch (node.nodeType) {
	case 1: { // ELEMENT_NODE
		var isLeaf = (node.childNodes.length == 0 && aardvark.leafElems[node.nodeName]);

		str += "<" + node.nodeName.toLowerCase() + " ";
		for (var i=0; i<node.attributes.length; i++) {
			if (node.attributes.item(i).nodeValue != null &&
				node.attributes.item(i).nodeValue != '') {
				str += node.attributes.item(i).nodeName +
					"='" +
					node.attributes.item(i).nodeValue +
					"' ";
				}
			}
		if (isLeaf)
			str += " />";
		else {
			str += ">";

			for (var i=0; i<node.childNodes.length; i++)
				str += aardvark.getOuterHtml(node.childNodes.item(i));

			str += "</" +
				node.nodeName.toLowerCase() + ">"
			}
		}
		break;

	case 3:	//TEXT_NODE
		str += node.nodeValue;
		break;
	}
return str;
};


// borrowed from somewhere
aardvark.createCSSRule = function (selector, declaration) {
// test for IE (can i just use "aardvark.doc.all"?)
var ua = navigator.userAgent.toLowerCase();
var isIE = (/msie/.test(ua)) && !(/opera/.test(ua)) && (/win/.test(ua));

// create the style node for all browsers
var style_node = aardvark.doc.createElement("style");
style_node.setAttribute("type", "text/css");
style_node.setAttribute("media", "screen");

// append a rule for good browsers
if (!isIE)
	style_node.appendChild(aardvark.doc.createTextNode(selector + " {" + declaration + "}"));

// append the style node
aardvark.doc.getElementsByTagName("head")[0].appendChild(style_node);

// use alternative methods for IE
if (isIE && aardvark.doc.styleSheets && aardvark.doc.styleSheets.length > 0) {
	var last_style_node = aardvark.doc.styleSheets[aardvark.doc.styleSheets.length - 1];
	if (typeof(last_style_node.addRule) == "object"){
		var a = selector.split (",");
		for (var i=0; i<a.length; i++) {
			last_style_node.addRule(a[i], declaration);
			}
		}
	}
};

aardvark.trimSpaces = function (s) {
while (s.charAt(0) == ' ')
	s = s.substring(1);
while (s.charAt(s.length-1) == ' ')
	s = s.substring(0, s.length-1);
return s;
};

aardvark.escapeForJavascript = function (s) {
return s.replace(new RegExp("\n", "g"), " ").replace(new RegExp("\t", "g"), " ").replace(new RegExp("\"", "g"), "\\\"").replace(new RegExp("\'", "g"), "\\'").replace(new RegExp("<", "g"), "&lt;").replace(new RegExp(">", "g"), "&gt;");
};

/**********************************
 * aardvarkDBox.js *
 **********************************/

aardvark.killDbox = function(id) {
var d = aardvark.doc.getElementById ("aardvarkdbox-" + id);
if (d) {
	aardvark.doc.body.removeChild (d);
	return true;
	}
return false;
};

aardvark.dboxMouseDown = function(evt) {
if (!evt)
	evt = aardvark.window.event;

var s = "aardvarkdbox-";
var killDbox = false;
var elem = aardvark.getElemFromEvent (evt);
var doClose = false, doSelect = false, index;

while (elem) {
	if (elem.isAardvarkSelectLink)
		doSelect = true;
	else if (elem.isAardvarkCloseButton)
		doClose = true;

	if (elem.id && elem.id.indexOf (s) == 0) {
		if (doSelect) {
			var e;
			for (var i=0; i<elem.childNodes.length; i++) {
				e = elem.childNodes.item(i);
				if (e.isDboxInnerContainer) {
					highlightText (e);
					}
				}
			}
		else if (doClose) {
			aardvark.doc.body.removeChild (elem);
			aardvark.dBoxArray[parseInt (elem.id.substring(s.length))] = null;
			}
		else {
			aardvark.dragElement = elem;
			aardvark.dragStartPos = aardvark.getPos (elem);
			aardvark.dragClickX = aardvark.mousePosX;
			aardvark.dragClickY = aardvark.mousePosY;
			}
		if (evt.preventDefault)
			evt.preventDefault ();
		else
			evt.returnValue = false;
		return false;
		}
	elem = elem.parentNode;
	}
};

aardvark.dBoxId = 0;
aardvark.dBoxArray = [];

function AardvarkDBox (bgColor, dragger, upperLeft, hideScrollbar, title, addSelectLink) {
var outerDiv, f = null;

if (upperLeft)
	this.upperLeft = true;
this.dims = aardvark.getWindowDimensions ();
var dims = this.dims;
dims.width -= 15;
dims.height -= 15; // why?
this.bgColor = bgColor;

this.id = aardvark.dBoxId;

outerDiv = aardvark.doc.createElement ("DIV");
outerDiv.style.padding = "0";
outerDiv.style.position = "absolute";
outerDiv.style.top = dims.scrollY + "px";
outerDiv.style.left = dims.scrollX + "px";
outerDiv.style.zIndex = "100000";
outerDiv.style.width = (dims.width-20) + "px";
outerDiv.style.height = (dims.height-20) + "px";
outerDiv.id = "aardvarkdbox-" + aardvark.dBoxId;
outerDiv.className = "aardvarkdbox";

var draggerDiv = null;
if (dragger) {
	draggerDiv = aardvark.doc.createElement ("DIV");
	draggerDiv.style.cssFloat = "left";
	draggerDiv.style.styleFloat = "left";
	draggerDiv.style.fontFamily = "arial";
	draggerDiv.style.padding = "2px";
	draggerDiv.style.margin = "0";
	draggerDiv.style.height = "14px";

	outerDiv.appendChild (draggerDiv);
	var closer = aardvark.doc.createElement("IMG");

	closer.src = aardvark.resourcePrefix + "closedbox.gif";
	closer.style.cssFloat = "left";
	closer.style.styleFloat = "left";
	closer.style.width = "17px";
	closer.style.height = "17px";
	closer.alt = "close";
	closer.style.margin = "-2px 4px 0 0";
	closer.style.cursor = "pointer";
	closer.isAardvark = true;
	closer.isAardvarkCloseButton = true;
	draggerDiv.appendChild (closer);
	if (addSelectLink) {
		var a = aardvark.doc.createElement ("div")
		a.innerHTML = "select all";
		a.style.fontFamily = "arial";
		a.style.padding = '0';
		a.style.margin = '0';
		a.style.textDecoration = 'underline';
		a.style.cssFloat = "right";
		a.style.styleFloat = "right";
		a.style.color = "#008";
		a.style.fontSize = "11px";
		a.style.cursor = "pointer";
		a.isAardvarkSelectLink = true;
		draggerDiv.appendChild (a);
		}
	if (title) {
		draggerDiv.style.fontFamily = "arial";
		draggerDiv.style.textAlign = "left";
		draggerDiv.style.color = "#000";
		draggerDiv.style.visibility = "hidden";
		draggerDiv.style.fontSize = "12px";
		draggerDiv.appendChild (aardvark.doc.createTextNode (title));
		draggerDiv.appendChild (aardvark.doc.createElement ("br"));
		}
	aardvark.setHandler (draggerDiv, "mousedown", aardvark.dboxMouseDown);
	}
f = aardvark.doc.createElement ("DIV");
f.isDboxInnerContainer = true;
f.style.cssFloat = "left";
f.style.styleFloat = "left";
f.style.border = '0';
f.style.margin = '0';
f.style.padding = '4px';
f.style.fontFamily = "arial";
f.style.fontSize = "13px";
f.style.color = "#000";
if (hideScrollbar) {
	f.style.overflow = 'hidden';
	f.scrolling = "no";
	}
else
	f.style.overflow = 'auto';
outerDiv.appendChild (f);
aardvark.doc.body.appendChild (outerDiv);

this.outerContainer = outerDiv;
this.dragBar = draggerDiv;

this.innerContainer = f;
aardvark.dBoxArray[aardvark.dBoxId] = this;
aardvark.dBoxId++;

if (!aardvark.doc.didDboxCss) {
	aardvark.createCSSRule ("div.aardvarkdbox div,div.aardvarkdbox table,div.aardvarkdbox td,div.aardvarkdbox tr,div.aardvarkdbox p,div.aardvarkdbox a", "color: black; background-color: transparent; border: 0; font-family: arial; font-weight: normal; font-size: 13px; font-style: normal; text-align: left; text-decoration: none;  text-indent: 0;vertical-align: top; ");
	aardvark.createCSSRule ("div.aardvarkdbox table", "border-spacing:2px;border-collapse:separate;");
	aardvark.createCSSRule ("div.aardvarkdbox td", "text-align: center; vertical-align: middle");
	aardvark.createCSSRule ("div.aardvarkdbox a, div.aardvarkdbox a:visited", "color: #007;text-decoration: underline");
	aardvark.createCSSRule ("div.aardvarkdbox a:hover", "color: #00f;");
	aardvark.doc.didDboxCss = true;
	}
return this;
};

AardvarkDBox.prototype.show = function () {
var dims = this.dims;
var draggerHeight = 1;

if (this.dragBar)
	draggerHeight = 18;

var w = this.innerContainer.offsetWidth
if (!this.innerContainer.style.width || this.innerContainer.style.width != '')
	w += 25;
if (this.dragBar) {
	var w2 = this.dragBar.offsetWidth + 12;
	if (w2 > w)
		w = w2;
	this.dragBar.style.cssFloat = "";
	this.dragBar.style.styleFloat = "";
	}

if (w > dims.width - 20)
	w = dims.width - 20;
this.outerContainer.style.width = w + "px";
this.innerContainer.style.width = w + "px";

if ((diff = this.innerContainer.offsetWidth-w) > 0)
	this.innerContainer.style.width = (w - diff) + "px";

var h = this.innerContainer.offsetHeight, diff;
if (h > dims.height-45)
	h = dims.height-45;
this.outerContainer.style.height = (h + draggerHeight) + "px";
this.innerContainer.style.height = h + "px";

if ((diff = this.innerContainer.offsetHeight-h) > 0)
	this.innerContainer.style.height = (h - diff) + "px";

this.innerContainer.style.backgroundColor = this.bgColor;
var x, y;

if (this.upperLeft) {
	x = dims.scrollX + 20;
	y = dims.scrollY + 20;
	}
else {
	x = dims.scrollX + (dims.width / 2) - (w/2);
	y = dims.scrollY + (dims.height / 2) - (h/2);
	}
aardvark.moveElem (this.outerContainer, x, y);

this.outerContainer.style.border = '1px solid #000';
this.outerContainer.style.backgroundColor = "#888";
this.innerContainer.style.visibility = 'visible';

if (this.dragBar) {
	this.dragBar.style.backgroundColor = "#d8d7dc";
	this.dragBar.style.visibility = 'visible';
	}
aardvark.setAardvarkElem (this.outerContainer);
}

AardvarkDBox.prototype.close = function () {
aardvark.doc.body.removeChild (this.outerContainer)
};

function highlightText(elem) {
if (aardvark.doc.selection) {
	var r1 = aardvark.doc.body.createTextRange();
	r1.moveToElementText(elem);
	r1.setEndPoint("EndToEnd", r1);
	r1.moveStart('character', 4);
	r1.moveEnd('character', 8);
	r1.select();
	}
else {
	s = aardvark.window.getSelection();
	var r1 = aardvark.doc.createRange();
	r1.setStartBefore(elem);
	r1.setEndAfter(elem) ;
	s.addRange(r1);
	}
};

/**********************************
 * aardvarkCommands.js *
 **********************************/

//------------------------------------------------------------
aardvark.rip = function (elem) {
if (window.RemoveItPermanently)
	RemoveItPermanently.doRipNode(elem);
else {
	var dbox = new AardvarkDBox ("#fff", true);
	dbox.innerContainer.innerHTML = aardvark.strings.ripHelp;
	dbox.show ();
	}
return true;
}

//------------------------------------------------------------
aardvark.wider = function (elem) {
if (elem &&	elem.parentNode) {
	var newElem = aardvark.findValidElement (elem.parentNode);
	if (!newElem)
		return false;

	if (aardvark.widerStack && aardvark.widerStack.length>0 &&
		aardvark.widerStack[aardvark.widerStack.length-1] == elem) {
		aardvark.widerStack.push (newElem);
		}
	else {
		aardvark.widerStack = [elem, newElem];
		}
	aardvark.selectedElem = newElem;
	aardvark.showBoxAndLabel (newElem,
			aardvark.makeElementLabelString (newElem));
	aardvark.didWider = true;
	return true;
	}
return false;
}

//------------------------------------------------------------
aardvark.narrower = function (elem) {
if (elem) {
	if (aardvark.widerStack && aardvark.widerStack.length>1 &&
		aardvark.widerStack[aardvark.widerStack.length-1] == elem) {
		aardvark.widerStack.pop();
		newElem = aardvark.widerStack[aardvark.widerStack.length-1];
		aardvark.selectedElem = newElem;
		aardvark.showBoxAndLabel (newElem,
				aardvark.makeElementLabelString (newElem));
		aardvark.didWider = true;
		return true;
		}
	}
return false;
}

//------------------------------------------------------------
aardvark.quit = function () {
aardvark.doc.aardvarkRunning = false;

if (aardvark.doc.all) {
	aardvark.doc.detachEvent ("onmouseover", aardvark.mouseOver);
	aardvark.doc.detachEvent ("onmousemove", aardvark.mouseMove);
	aardvark.doc.detachEvent ("onkeypress", aardvark.keyDown);
	aardvark.doc.detachEvent ("onmouseup", aardvark.mouseUp, false);
	}
else {
	aardvark.doc.removeEventListener("mouseover", aardvark.mouseOver, false);
	aardvark.doc.removeEventListener("mousemove", aardvark.mouseMove, false);
	aardvark.doc.removeEventListener("mouseup", aardvark.mouseUp, false);
	aardvark.doc.removeEventListener("keypress", aardvark.keyDown, false);
	}

aardvark.removeBoxFromBody ();

delete (aardvark.selectedElem);
if (aardvark.widerStack)
	delete (aardvark.widerStack);
return true;
}

//------------------------------------------------------------
aardvark.suspend = function () {
if (aardvark.doc.all) {
	aardvark.doc.detachEvent ("onmouseover", aardvark.mouseOver);
	aardvark.doc.detachEvent ("onkeypress", aardvark.keyDown);
	}
else {
	aardvark.doc.removeEventListener("mouseover", aardvark.mouseOver, false);
	aardvark.doc.removeEventListener("keypress", aardvark.keyDown, false);
	}
return true;
}

//------------------------------------------------------------
aardvark.resume = function () {
if (aardvark.doc.all) {
	aardvark.doc.attachEvent ("onmouseover", aardvark.mouseOver);
	aardvark.doc.attachEvent ("onkeypress", aardvark.keyDown);
	}
else {
	aardvark.doc.addEventListener ("mouseover", aardvark.mouseOver, false);
	aardvark.doc.addEventListener ("keypress", aardvark.keyDown, false);
	}
return true;
}

//------------------------------------------------------------
aardvark.viewSource = function (elem) {
var dbox = new AardvarkDBox ("#fff", true, false, false, aardvark.strings.viewHtmlSource, true);
var v = aardvark.getOuterHtmlFormatted(elem, 0);
dbox.innerContainer.innerHTML = v;

if (!aardvark.doc.didViewSourceDboxCss) {
	aardvark.createCSSRule ("div.aardvarkdbox div", "font-size: 13px; margin: 0; padding: 0;");
	aardvark.createCSSRule ("div.aardvarkdbox div.vsblock", "font-size: 13px; border: 1px solid #ccc; border-right: 0;margin: -1px 0 -1px 1em; padding: 0;");
	aardvark.createCSSRule ("div.aardvarkdbox div.vsline", "font-size: 13px; border-right: 0;margin: 0 0 0 .6em;text-indent: -.6em; padding: 0;");
	aardvark.createCSSRule ("div.aardvarkdbox div.vsindent", "font-size: 13px; border-right: 0;margin: 0 0 0 1.6em;text-indent: -.6em; padding: 0;");
	aardvark.createCSSRule ("div.aardvarkdbox span.tag", "color: #c00;font-weight:bold;");
	aardvark.createCSSRule ("div.aardvarkdbox span.pname", "color: #080;font-weight: bold;");
	aardvark.createCSSRule ("div.aardvarkdbox span.pval", "color:#00a;font-weight: bold;");
	aardvark.createCSSRule ("div.aardvarkdbox span.aname", "color: #050;font-style: italic;font-weight: normal;");
	aardvark.createCSSRule ("div.aardvarkdbox span.aval", "color:#007;font-style: italic;font-weight: normal;");
	aardvark.doc.didViewSourceDboxCss = true;
	}
dbox.show ();
return true;
}

//------------------------------------------------------------
aardvark.colorize = function (elem) {
elem.style.backgroundColor = "#" +
		Math.floor(Math.random()*16).toString(16) +
		Math.floor(Math.random()*16).toString(16) +
		Math.floor(Math.random()*16).toString(16);
elem.style.backgroundImage = "";
return true;
}
//------------------------------------------------------------
aardvark.removeElement = function (o) {
if (o.parentNode != null) {
	var tmpUndoData = {};
	tmpUndoData.mode = 'R';
	tmpUndoData.elem = o;
	o.style.display = 'none';
	tmpUndoData.next = aardvark.undoData;
	aardvark.undoData = tmpUndoData;
	aardvark.clearBox ();
	return true;
	}
return false;
}

//------------------------------------------------------------
aardvark.paste = function (o) {
if (o.parentNode != null) {
	if (aardvark.undoData.mode == "R") {
		e = aardvark.undoData.elem;
		if (e.nodeName == "TR" && o.nodeName != "TR") {
			var t = aardvark.doc.createElement ("TABLE");
			var tb = aardvark.doc.createElement ("TBODY");
			t.appendChild (tb);
			e.parentNode.removeChild (e);
			e.style.display = '';
			tb.appendChild (e);
			e = t;
			}
		else if (e.nodeName == "TD" && o.nodeName != "TD") {
			var t2 = aardvark.doc.createElement ("DIV");

			var len = e.childNodes.length, i, a = new Array();

			for (i=0; i<len; i++)
				a[i] = e.childNodes.item(i);

			for (i=0; i<len; i++) {
				e.removeChild(a[i]);
				t2.appendChild (e);
				}
			e.parentNode.removeChild (e);
			t2.appendChild (e);
			e = t2;
			}
		else {
			e.parentNode.removeChild (aardvark.undoData.elem);
			e.style.display = '';
			}

		if (o.nodeName == "TD" && e.nodeName != "TD")
			o.insertBefore (e, o.firstChild);
		else if (o.nodeName == "TR" && e.nodeName != "TR")
			o.insertBefore (e, o.firstChild.firstChild);
		else
			o.parentNode.insertBefore (e, o);
		aardvark.clearBox ();
		aardvark.undoData = aardvark.undoData.next;
		}
	}
return true;
}

//------------------------------------------------------------
aardvark.isolateElement = function (o) {
if (o.parentNode != null) {
	aardvark.clearBox ();

	var clone;

	if (document.all) {
		// this hack prevents a crash on cnn.com
		if (o.tagName == "TR" || o.tagName == "TD") {
			var t = aardvark.doc.createElement ("TABLE");
			var tb = aardvark.doc.createElement ("TBODY");
			t.appendChild (tb);

			if (o.tagName == "TD") {
				var tr = aardvark.doc.createElement ("TR");
				var td = aardvark.doc.createElement ("TD");
				td.innerHTML = o.innerHTML;
				tr.appendChild (td);
				tb.appendChild (tr);
				}
			else {
				var tr = aardvark.doc.createElement ("TR");
				var len = o.childNodes.length;

				for (var i=0; i<len; i++) {
					var td = o.childNodes.item(i);
					if (td.nodeName == "TD") {
						var newTd = aardvark.doc.createElement ("TD");
						newTd.innerHTML = td.innerHTML;
						tr.appendChild (newTd);
						}
					}
				tb.appendChild (tr);
				}
			clone = t;
			}
		else {
			var div = document.createElement ("DIV");
			div.innerHTML = o.outerHTML;
			clone = div.firstChild;
			}
		}
	else {
		clone = o.cloneNode (true);
		}

	clone.style.textAlign = "";
	clone.style.cssFloat = "none";
	clone.style.styleFloat = "none";
	clone.style.position = "";
	clone.style.padding = "5px";
	clone.style.margin = "5px";

	if (clone.tagName == "TR" || clone.tagName == "TD") {
		if (clone.tagName == "TD") {
			var tr = aardvark.doc.createElement ("TR");
			tr.appendChild (clone);
			clone = tr;
			}
		var t = aardvark.doc.createElement ("TABLE");
		var tb = aardvark.doc.createElement ("TBODY");
		t.appendChild (tb);
		tb.appendChild (clone);
		clone = t;
		}

	var tmpUndoData = [];
	var len = aardvark.doc.body.childNodes.length, i, count = 0, e;

	for (i=0; i<len; i++) {
		e = aardvark.doc.body.childNodes.item(i);
		if (!e.isAardvark) {
			tmpUndoData[count] = e;
			count++;
			}
		}
	tmpUndoData.numElems = count;

	for (i=count-1; i>=0; i--)
		aardvark.doc.body.removeChild (tmpUndoData[i]);

	tmpUndoData.mode = 'I';
	tmpUndoData.bg = aardvark.doc.body.style.background;
	tmpUndoData.bgc = aardvark.doc.body.style.backgroundColor;
	tmpUndoData.bgi = aardvark.doc.body.style.backgroundImage;
	tmpUndoData.m = aardvark.doc.body.style.margin;
	tmpUndoData.ta = aardvark.doc.body.style.textAlign;
	tmpUndoData.next = aardvark.undoData;
	aardvark.undoData = tmpUndoData;

	aardvark.doc.body.style.width = "100%";
	aardvark.doc.body.style.background = "none";
	aardvark.doc.body.style.backgroundColor = "white";
	aardvark.doc.body.style.backgroundImage = "none";
	aardvark.doc.body.style.textAlign = "left";

//	clone.style.width = "400px";
	aardvark.doc.body.appendChild (clone);

	//aardvark.makeElems ();
	aardvark.window.scroll (0, 0);
	}
return true;
}

//-------------------------------------------------
aardvark.deWidthify = function (node, skipClear) {
switch (node.nodeType) {
	case 1: // ELEMENT_NODE
		{
		if (node.tagName != "IMG") {
			node.style.width = 'auto';
			if (node.width)
				node.width = null;
			}
		var isLeaf = (node.childNodes.length == 0 && aardvark.leafElems[node.nodeName]);

		if (!isLeaf)
			for (var i=0; i<node.childNodes.length; i++)
				aardvark.deWidthify (node.childNodes.item(i));
		}
		break;
	}
if (!skipClear)
	aardvark.clearBox ();
return true;
}

//--------------------------------------------------------
aardvark.blackOnWhite = function (node, isLink) {
// this could be done way better using the createCSSRule thing
switch (node.nodeType) {
	case 1: // ELEMENT_NODE
		{
		if (node.tagName != "IMG") {
			if (node.tagName == "A")
				isLink = true;
			node.style.color = "#000";
//			node.style.color = (isLink)?"#006":"#000";
			if (isLink)
				node.style.textDecoration = "underline";
			node.style.backgroundColor = "#fff";
			node.style.fontFamily = "arial";
			node.style.fontSize = "13px";
			node.style.textAlign = "left";
			node.align = "left";
			node.style.backgroundImage = "";

			var isLeaf = (node.childNodes.length == 0 && aardvark.leafElems[node.nodeName]);

			if (!isLeaf)
				for (var i=0; i<node.childNodes.length; i++)
					aardvark.blackOnWhite(node.childNodes.item(i), isLink);
			}
		}
		break;
	}
return true;
}

//--------------------------------------------------------
aardvark.getOuterHtmlFormatted = function (node, indent) {
var str = "";

if (aardvark.doc.all)	{
	return "<pre>" + node.outerHTML.replace(/\</g, '&lt;').replace(/\>/g, '&gt;') + "</pre>";
	}

switch (node.nodeType) {
	case 1: // ELEMENT_NODE
		{
		if (node.style.display == 'none')
			break;
		var isLeaf = (node.childNodes.length == 0 && aardvark.leafElems[node.nodeName]);
		var isTbody = (node.nodeName == "TBODY" && node.attributes.length == 0);

		if (isTbody) {
			for (var i=0; i<node.childNodes.length; i++)
				str += aardvark.getOuterHtmlFormatted(node.childNodes.item(i), indent);
			}
		else {
			if (isLeaf)
				str += "\n<div class='vsindent'>\n";
			else if (indent>0)
				str += "\n<div class='vsblock' style=''>\n<div class='vsline'>\n";
			else
				str += "\n<div class='vsline'>\n";

			str += "&lt;<span class='tag'>" +
						node.nodeName.toLowerCase() + "</span>";
			for (var i=0; i<node.attributes.length; i++) {
				if (node.attributes.item(i).nodeValue != null &&
					node.attributes.item(i).nodeValue != '') {
					str += " <span class='pname'>"
					str += node.attributes.item(i).nodeName;

					if (node.attributes.item(i).nodeName == "style") {
						var styles = "";
						var a = node.attributes.item(i).nodeValue.split(";");
						for (var j=0; j<a.length; j++) {
							var pair = a[j].split (":");
							if (pair.length == 2) {
								var s = aardvark.trimSpaces(pair[0]), index;
								styles += "; <span class='aname'>" + s + "</span>: <span class='aval'>" + aardvark.trimSpaces(pair[1]) + "</span>";
								}
							}
						styles = styles.substring (2);
						str += "</span>=\"" +  styles + "\"";
						}
					else {
						str += "</span>=\"<span class='pval'>" +  node.attributes.item(i).nodeValue + "</span>\"";
						}
					}
				}
			if (isLeaf)
				str += " /&gt;\n</div>\n";
			else {
				str += "&gt;\n</div>\n";
				for (var i=0; i<node.childNodes.length; i++)
					str += aardvark.getOuterHtmlFormatted(node.childNodes.item(i), indent+1);
				str += "\n<div class='vsline'>\n&lt;/<span class='tag'>" +
					node.nodeName.toLowerCase() + "</span>&gt;\n</div>\n</div>\n"
				}
			}
		}
		break;

	case 3:	//TEXT_NODE
		{
		var v = node.nodeValue;
		v = v.replace ("<", "&amp;lt;").replace (">", "&amp;gt;");

		v = aardvark.trimSpaces (v);
		if (v != '' && v != '\n'
				&& v != '\r\n' && v.charCodeAt(0) != 160)
			str += "<div class='vsindent'>" + v + "</div>";
		}
		break;

	case 4: // CDATA_SECTION_NODE
		str += "<div class='vsindent'>&lt;![CDATA[" + node.nodeValue + "]]></div>";
		break;

	case 5: // ENTITY_REFERENCE_NODE
		str += "&amp;" + node.nodeName + ";<br>"
		break;

	case 8: // COMMENT_NODE
		str += "<div class='vsindent'>&lt;!--" + node.nodeValue + "--></div>"
		break;
	}
return str;
};

aardvark.camelCaseProps = {
	'colspan': 'colSpan',
	'rowspan': 'rowSpan',
	'accesskey': 'accessKey',
	'class': 'className',
	'for': 'htmlFor',
	'tabindex': 'tabIndex',
	'maxlength': 'maxLength',
	'readonly': 'readOnly',
	'frameborder': 'frameBorder',
	'cellspacing': 'cellSpacing',
	'cellpadding': 'cellPadding'
};

//--------------------------------------------------------
aardvark.domJavascript = function (node, indent) {
var indentStr = "";
for (var c=0; c<indent; c++)
	indentStr += "  ";

switch (node.nodeType) {
	case 1: // ELEMENT_NODE
		{
		if (node.style.display == 'none')
			break;

		var isLeaf = (node.childNodes.length == 0 && aardvark.leafElems[node.nodeName]);

		var children = "", numChildren = 0, t, useInnerHTML = false;
		if (!isLeaf) {
			for (var i=0; i<node.childNodes.length; i++) {
				t = aardvark.domJavascript(node.childNodes.item(i), indent+1);
				if (t == "useInnerHTML") {
					useInnerHTML = true;
					break;
					}
				if (t) {
					children += indentStr + "  " + t + ",\n";
					numChildren++;
					}
				}
			//	children = indentStr + "   [\n" + children.substring(0, children.length-2) + "\n" + indentStr + "   ]\n";
			if (numChildren && !useInnerHTML)
				children = children.substring(0, children.length-2) + "\n";
			}

		var properties = "", styles = "", numProps = 0, sCount = 0;

		for (var i=0; i<node.attributes.length; i++) {
			if (node.attributes.item(i).nodeValue != null && node.attributes.item(i).nodeValue != '') {
				var n = node.attributes.item(i).nodeName,
					 v = node.attributes.item(i).nodeValue;

				switch (n) {
					case "style": {
						var a = node.attributes.item(i).nodeValue.split(";");
						for (var j=0; j<a.length; j++) {
							var pair = a[j].split (":");
							if (pair.length == 2) {
								var s = aardvark.trimSpaces(pair[0]), index;
								while ((index = s.indexOf("-")) != -1)
									s = s.substring(0, index) + s.charAt(index+1).toUpperCase() + s.substring(index+2);

								if (s == "float") { // yuk
									styles += ", <span style='color:#060; font-style:italic'>styleFloat</span>: \"<span style='color:#008;font-style:italic'>" + aardvark.trimSpaces(pair[1]) + "</span>\", <span style='color:#060; font-style:italic'>cssFloat</span>: \"<span style='color:#008;font-style:italic'>" + aardvark.trimSpaces(pair[1]) + "</span>\"";
									}
								else {
									styles += ", <span style='color:#060; font-style:italic'>" + s + "</span>: \"<span style='color:#008;font-style:italic'>" + aardvark.trimSpaces(pair[1]) + "</span>\"";
									}
								sCount++;
								}
							}
						styles = styles.substring (2);
						break;
						}
					default:
						{
						var newN;
						if ((newIn = aardvark.camelCaseProps[n]) != null)
							n = newIn;
						properties += ", <span style='color:#080;font-weight: bold'>" + n + "</span>:\"<span style='color:#00b;font-weight: bold'>" + v + "</span>\"";
						numProps++;
						break;
						}
					}
				}
			}

		if (useInnerHTML) {
			var ih = node.innerHTML, index;

			if ((index = ih.indexOf("useInnerHTML")) != -1) {
				ih = ih.substring(index + "useInnerHTML".length);
				if (index = ih.indexOf("->") != -1)
					ih = ih.substring(index+3);
				}

			properties += ", <span style='color:#080;font-weight: bold'>innerHTML</span>:\"<span style='color:#00b;font-weight: bold'>" +  aardvark.escapeForJavascript (ih) + "</span>\"";
			numProps++;
			numChildren = 0;
			}

		if (styles != "") {
			properties = "{<span style='color:#080;font-weight: bold'>style</span>:{" + styles + "}" + properties + "}";
			numProps++;
			}
		else
			properties = "{" + properties.substring(2) + "}";

		// element does not start with an indent, does not end with a linefeed or comma
		// children string starts with indent, has indent for each child

		str = "[\"<span style='color:red;font-weight:bold'>" + node.nodeName.toLowerCase() + "</span>\"";

		if (numChildren)
			if (numProps)
				return str + ", " + properties + ",\n" + children + indentStr + "]";
			else
				return str + ",\n" + children + indentStr + "]";
		else
			if (numProps)
				return str + ", " + properties  + "]";
			else
				return str + "]";
		}
		break;

	case 3:	//TEXT_NODE
		{
		var n = node.nodeValue;
		if (node.nodeValue != '')
			n = aardvark.escapeForJavascript (n);


		n = aardvark.trimSpaces (n);
		if (n.length > 0)
			return "\"<b>" + n + "</b>\"";
		}
		break;

	case 4: // CDATA_SECTION_NODE
		break;

	case 5: // ENTITY_REFERENCE_NODE
		break;

	case 8: // COMMENT_NODE
		if (node.nodeValue.indexOf("useInnerHTML") != -1)
			return "useInnerHTML";
		break;
	}
return null;
}

//------------------------------------------------------------
aardvark.makeJavascript = function (elem) {
var dbox = new AardvarkDBox ("#fff", true, false, false, aardvark.strings.javascriptDomCode, true);
dbox.innerContainer.innerHTML = "<pre style=\"margin:3; width: 97%\">" + aardvark.domJavascript(elem, 0) + "</pre><br>";
dbox.show ();
return true;
}

//-------------------------------------------------
aardvark.undo = function () {
if (aardvark.undoData == null)
	return false;
aardvark.clearBox ();
switch (aardvark.undoData.mode) {
	case "I": {
		var a = [];
		var len = aardvark.doc.body.childNodes.length, i, count = 0, e;

		for (i=0; i<len; i++)
			{
			e = aardvark.doc.body.childNodes.item (i);
			if (!e.isAardvark)
				{
				a[count] = e;
				count++;
				}
			}
		for (i=count-1; i>=0; i--)
			aardvark.doc.body.removeChild (a[i]);

		len =	aardvark.undoData.numElems;
		for (i=0; i<len; i++)
			aardvark.doc.body.appendChild (aardvark.undoData[i]);

		aardvark.doc.body.style.background = aardvark.undoData.bg;
		aardvark.doc.body.style.backgroundColor = aardvark.undoData.bgc;
		aardvark.doc.body.style.backgroundImage = aardvark.undoData.bgi;
		aardvark.doc.body.style.margin = aardvark.undoData.m;
		aardvark.doc.body.style.textAlign = aardvark.undoData.ta;
		break;
		}
	case "R": {
		aardvark.undoData.elem.style.display = '';
		break;
		}
	default:
		return false;
	}
aardvark.undoData = aardvark.undoData.next;
return true;
}

//-------------------------------------------------
aardvark.showMenu = function () {
if (aardvark.helpBoxId) {
	if (aardvark.killDbox (aardvark.helpBoxId) == true) {
		delete (aardvark.helpBoxId);
		return;
		}
	}
var s = "<table style='margin:5px 10px 0 10px'>";
for (var i in aardvark.commands)	{
	s += "<tr><td style='padding: 3px 7px; border: 1px solid black; font-family: courier; font-weight: bold;" +
		"background-color: #fff'>" + i +
		"</td><td style='padding: 3px 7px; font-size: .9em;  text-align: left;'>" + aardvark.commands[i].name + "</td></tr>";
	}
s += "</table><br>" + aardvark.strings.karmaticsPlug;

var dbox = new AardvarkDBox ("#fff2db", true, true, true, aardvark.strings.aardvarkKeystrokes);
dbox.innerContainer.innerHTML = s;
dbox.show ();
aardvark.helpBoxId = dbox.id;
return true;
};

//-------------------------------------------------
aardvark.condorcet = function (elem) {
var trs = elem.getElementsByTagName ("TR");
var candidate1, candidate2;
var s = "";
var snames = "";
var CANDIDATE_IDS =
 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";

for (var i=2; i<trs.length; i++) {
	tr = trs[i];
	candidate1 = i-2;
	var tds = tr.getElementsByTagName ("TD");
	var e = tds[0];
	while (e.firstChild)
		e = e.firstChild;
	snames += e.nodeValue + "\n";
	for (var j=i; j<tds.length; j++) {
		candidate2 = j-1;

		var e = tds[j];
		while (e.firstChild)
			e = e.firstChild;

		var tr2 = trs[candidate2+2];
		var tds2 = tr2.getElementsByTagName ("TD");
		var e2 = tds2[candidate1+1];
		while (e2.firstChild)
			e2 = e2.firstChild;

	//	s += CANDIDATE_IDS.charAt(candidate1) + "," + CANDIDATE_IDS.charAt(candidate2) + " : " + e.nodeValue +  "," + e2.nodeValue + "\n";
		s += e.nodeValue +  "," + e2.nodeValue + "\n";
		//tds[j].innerHTML = CANDIDATE_IDS.charAt(candidate1) + "," + CANDIDATE_IDS.charAt(candidate2);
		}
	}
var dbox = new AardvarkDBox ("#fff", true, false, false, aardvark.strings.javascriptDomCode, true);
dbox.innerContainer.innerHTML = "<pre style=\"margin:3; width: 97%\">" + snames + "<br><br>" + s + "</pre><br>";
dbox.show ();
return true;
};


//------------------------------------------------------------

aardvark.loadCommands = function () {
// 0: name (member of aardvark.strings, or literal string)
// 1: function
// 2: needs element
// 3: 'true' for extension only
var commands =
	[
	["wider", aardvark.wider, true],
	["narrower", aardvark.narrower, true],
	["undo", aardvark.undo, false],
	["quit", aardvark.quit, false],
	["remove", aardvark.removeElement, true],
	["kill", aardvark.rip, true, true],
	["isolate", aardvark.isolateElement, true],
	["blackOnWhite", aardvark.blackOnWhite, true],
	["deWidthify", aardvark.deWidthify, true],
	["colorize", aardvark.colorize, true],
	["viewSource", aardvark.viewSource, true],
	["javascript", aardvark.makeJavascript, true],
	["paste", aardvark.paste, true],
	["help", aardvark.showMenu, false],
	["x", aardvark.condorcet, true]
	];

aardvark.commands = {};
for (var i=0; i<commands.length; i++) {
	var name = commands[i][0];
	// skip if bookmarklet and command is ff ext. only
	if (!(aardvark.isBookmarklet && commands[i][3])) {
		if (aardvark.strings[name] && aardvark.strings[name] != "")
			name = aardvark.strings[name];
		var key, keyOffset = name.indexOf('&');
		if (keyOffset != -1) {
			key = name.charAt(keyOffset+1);
			name = name.substring (0, keyOffset) + name.substring (keyOffset+1);
			}
		else {
			key = name.charAt(0);
			keyOffset = 0;
			}
		aardvark.commands[key] = {name: name, keyOffset: keyOffset, func: commands[i][1], needsElement: commands[i][2]};

		}
	}
}

/**********************************
 * aardvarkMain.js *
 **********************************/

//-------------------------------------------------
aardvark.showHelpTip = function (diff) {
var dbox = new AardvarkDBox ("#fff2db", false, true, true);
dbox.innerContainer.innerHTML = "<p style='clear: both; margin: 3px 0 0 0;'><img src='" +  aardvark.resourcePrefix + "aardvarkhelp.gif' style=' float: right; margin: 0 0 0px 0'>" + aardvark.strings.initialTipText + "</p>";
dbox.innerContainer.style.width = "14em";
dbox.innerContainer.style.height = "54px";
dbox.show ();
setTimeout ("aardvark.killDbox(" + dbox.id + ")", 2000);
return true;
};

//-------------------------------------------------
// create the box and tag etc (done once and saved)
aardvark.makeElems = function () {
aardvark.borderElems = [];
var d, i;

for (i=0; i<4; i++) {
	d = aardvark.doc.createElement ("DIV");
	d.style.display = "none";
	d.style.overflow = "hidden";
	d.style.position = "absolute";
	d.style.height = "2px";
	d.style.width = "2px";
	d.style.top = "20px";
	d.style.left = "20px";
	d.style.zIndex = "5001";
	d.isAardvark = true; // mark as ours
	aardvark.borderElems[i] = d;
	aardvark.doc.body.appendChild (d);
	}

aardvark.borderElems[0].style.borderTopWidth = "2px";
aardvark.borderElems[0].style.borderTopColor = "#f00";
aardvark.borderElems[0].style.borderTopStyle = "solid";
aardvark.borderElems[1].style.borderBottomWidth = "2px";
aardvark.borderElems[1].style.borderBottomColor = "#f00";
aardvark.borderElems[1].style.borderBottomStyle = "solid";
aardvark.borderElems[2].style.borderLeftWidth = "2px";
aardvark.borderElems[2].style.borderLeftColor = "#f00";
aardvark.borderElems[2].style.borderLeftStyle = "solid";
aardvark.borderElems[3].style.borderRightWidth = "2px";
aardvark.borderElems[3].style.borderRightColor = "#f00";
aardvark.borderElems[3].style.borderRightStyle = "solid";

d = aardvark.doc.createElement ("DIV");
aardvark.setElementStyleDefault (d, "#fff0cc");
d.isAardvark = true; // mark as ours
d.isLabel = true; //
d.style.borderTopWidth = "0";
d.style.MozBorderRadiusBottomleft = "6px";
d.style.MozBorderRadiusBottomright = "6px";
d.style.zIndex = "5005";
d.style.visibility = "hidden";
aardvark.doc.body.appendChild (d);
aardvark.labelElem = d;

d = aardvark.doc.createElement ("DIV");
aardvark.setElementStyleDefault (d, "#dfd");
d.isAardvark = true; // mark as ours
d.isKeybox = true; //
d.style.backgroundColor = "#cfc";
d.style.zIndex = "5006";
aardvark.doc.body.appendChild (d);
aardvark.keyboxElem = d;
};

//-------------------------------------------------
// show the red box around the element, and display
// the string in the little tag
aardvark.showBoxAndLabel = function (elem, string) {
var pos = aardvark.getPos(elem)
var dims = aardvark.getWindowDimensions ();
var y = pos.y;

aardvark.moveElem (aardvark.borderElems[0], pos.x, y);
aardvark.borderElems[0].style.width = elem.offsetWidth + "px";
aardvark.borderElems[0].style.display = "";

aardvark.moveElem (aardvark.borderElems[1], pos.x, y+elem.offsetHeight-2);
aardvark.borderElems[1].style.width = (elem.offsetWidth + 2)  + "px";
aardvark.borderElems[1].style.display = "";

aardvark.moveElem (aardvark.borderElems[2], pos.x, y);
aardvark.borderElems[2].style.height = elem.offsetHeight  + "px";
aardvark.borderElems[2].style.display = "";

aardvark.moveElem (aardvark.borderElems[3], pos.x+elem.offsetWidth-2, y);
aardvark.borderElems[3].style.height = elem.offsetHeight + "px";
aardvark.borderElems[3].style.display = "";

y += elem.offsetHeight + 2;

aardvark.labelElem.innerHTML = string;
aardvark.labelElem.style.display = '';

// adjust the label as necessary to make sure it is within screen and
// the border is pretty
if ((y + aardvark.labelElem.offsetHeight) >= dims.scrollY + dims.height) {
	aardvark.labelElem.style.borderTopWidth = "1px";
	aardvark.labelElem.style.MozBorderRadiusTopleft = "6px";
	aardvark.labelElem.style.MozBorderRadiusTopright = "6px";
	aardvark.labelDrawnHigh = true;
	y = (dims.scrollY + dims.height) - aardvark.labelElem.offsetHeight;
	}
else if (aardvark.labelElem.offsetWidth > elem.offsetWidth) {
	aardvark.labelElem.style.borderTopWidth = "1px";
	aardvark.labelElem.style.MozBorderRadiusTopright = "6px";
	aardvark.labelDrawnHigh = true;
	}
else if (aardvark.labelDrawnHigh) {
	aardvark.labelElem.style.borderTopWidth = "0";
	aardvark.labelElem.style.MozBorderRadiusTopleft = "";
	aardvark.labelElem.style.MozBorderRadiusTopright = "";
	delete (aardvark.labelDrawnHigh);
	}
aardvark.moveElem (aardvark.labelElem, pos.x+2, y);
aardvark.labelElem.style.visibility = "visible";
};

//-------------------------------------------------
aardvark.removeBoxFromBody = function () {
if (aardvark.labelElem) {
	aardvark.doc.body.removeChild(aardvark.labelElem);
	aardvark.labelElem = null;
	}
if (aardvark.keyboxElem) {
	aardvark.doc.body.removeChild(aardvark.keyboxElem);
	aardvark.keyboxElem = null;
	}
if (aardvark.borderElems != null) {
	for (var i=0; i<4; i++)
		aardvark.doc.body.removeChild(aardvark.borderElems[i]);
	aardvark.borderElems = null;
	}
};

//-------------------------------------------------
// remove the red box and tag
aardvark.clearBox = function () {
aardvark.selectedElem = null;
if (aardvark.borderElems != null) {
	for (var i=0; i<4; i++)
		aardvark.borderElems[i].style.display = "none";
	aardvark.labelElem.style.display = "none";
	aardvark.labelElem.style.visibility = "hidden";
	}
};

//-------------------------------------------------
aardvark.hideKeybox = function () {
aardvark.keyboxElem.style.display = "none";
aardvark.keyboxTimeoutHandle = null;
};

//-------------------------------------------------
aardvark.showKeybox = function (command){
if (aardvark.keyboxElem == null)
	return;

var s1 = command.name.substring(0, command.keyOffset);
var s2 = command.name.substring(command.keyOffset+1);

aardvark.keyboxElem.innerHTML = s1 + "<b style='font-size:2em;'>" +
		command.name.charAt(command.keyOffset) + "</b>" + s2;

var dims = aardvark.getWindowDimensions ();
var y = dims.scrollY + aardvark.mousePosY + 10;
if (y < 0)
	y = 0;
else if (y > (dims.scrollY + dims.height) - 30)
	y = (dims.scrollY + dims.height) - 60;
var x = aardvark.mousePosX + 10;
if (x < 0)
	x = 0;
else if (x > (dims.scrollX + dims.width) - 60)
	x = (dims.scrollX + dims.width) - 100;

aardvark.moveElem (aardvark.keyboxElem, x, y);
aardvark.keyboxElem.style.display = "";
if (aardvark.keyboxTimeoutHandle)
	clearTimeout (aardvark.keyboxTimeoutHandle);
aardvark.keyboxTimeoutHandle = setTimeout ("aardvark.hideKeybox()", 400);
};

aardvark.validIfBlockElements = {
	SPAN: 1,
	A: 1
	};

aardvark.validIfNotInlineElements = {
	UL: 1,
	LI: 1,
	OL: 1,
	PRE: 1,
	CODE: 1
	};

aardvark.alwaysValidElements = {
	DIV: 1,
	IFRAME: 1,
	OBJECT: 1,
	APPLET: 1,
	BLOCKQUOTE: 1,
	H1: 1,
	H2: 1,
	H3: 1,
	FORM: 1,
	P: 1,
	TABLE: 1,
	TD: 1,
	TH: 1,
	TR: 1,
	IMG: 1
	};

// safari can't seem to get the dimensions of a TR....(wtf?)
// if (aardvark.isSafari)
// delete aardvark.alwaysValidElements["TR"];

//-------------------------------------------------
// given an element, walk upwards to find the first
// valid selectable element
aardvark.findValidElement = function (elem) {
while (elem) {
	if (aardvark.alwaysValidElements[elem.tagName])
		return elem;
	else if (aardvark.validIfBlockElements[elem.tagName]) {
		if (aardvark.doc.defaultView) {
			if (aardvark.doc.defaultView.getComputedStyle
						(elem, null).getPropertyValue("display") == 'block')
				return elem;
			}
		else if (elem.currentStyle){
			if (elem.currentStyle["display"] == 'block')
				return elem;
			}
		}
	else if (aardvark.validIfNotInlineElements[elem.tagName]){
		if (aardvark.doc.defaultView) {
			if (aardvark.doc.defaultView.getComputedStyle
						(elem, null).getPropertyValue("display") != 'inline')
				return elem;
			}
		else if (elem.currentStyle) {
			if (elem.currentStyle["display"] != 'inline')
				return elem;
			}
		}
	elem = elem.parentNode;
	}
return elem;
};

//-------------------------------------------------
aardvark.makeElementLabelString = function (elem) {
var s = "<b style='color:#000'>" + elem.tagName.toLowerCase() + "</b>";
if (elem.id != '')
	s += ", id: " + elem.id;
if (elem.className != '')
	s += ", class: " + elem.className;
return s;
};

//-------------------------------------------------
aardvark.mouseUp = function (evt) {
if (aardvark.dragElement) {
	delete aardvark.dragElement;
	delete aardvark.dragClickX;
	delete aardvark.dragClickY;
	delete aardvark.dragStartPos;
	}
return false;
};

// the following three functions are the main event handlers
//-------------------------------------------------
aardvark.mouseMove = function (evt) {
if (!evt)
	evt = aardvark.window.event;

if (aardvark.mousePosX == evt.clientX &&
			aardvark.mousePosY == evt.clientY) {
	aardvark.moved = false;
	return;
	}

aardvark.mousePosX  = evt.clientX;
aardvark.mousePosY = evt.clientY;

// this drags the dialog box, if one exists
if (aardvark.dragElement) {
	aardvark.moveElem (aardvark.dragElement,
			(aardvark.mousePosX - aardvark.dragClickX) + aardvark.dragStartPos.x,
			(aardvark.mousePosY - aardvark.dragClickY) + aardvark.dragStartPos.y);
	aardvark.moved = false;
	return true;
	}

aardvark.moved = true;
return false;
};

//-------------------------------------------------
aardvark.mouseOver = function (evt) {
if (!evt)
	evt = aardvark.window.event;

if (!aardvark.moved)
	return;

var elem = aardvark.getElemFromEvent (evt);
if (elem == null)	{
	aardvark.clearBox ();
	return;
	}


elem = aardvark.findValidElement (elem);

if (elem == null) {
	aardvark.clearBox();
	return;
	}

// note: this assumes that:
// 1. our display elements would be selectable types, and
// 2. elements inside display elements would not
if (elem.isAardvark) {
	if (elem.isKeybox)
		aardvark.hideKeybox();
	else if (elem.isLabel)
		aardvark.clearBox();
	else
		aardvark.isOnAardvarkElem = true;
	return;
	}

// this prevents it from snapping back to another element
// if you do a "wider" or "narrower" while on top of one
// of the border lines.  not fond of this, but its about
// the best i can do
if (aardvark.isOnAardvarkElem && aardvark.didWider) {
	var e = elem, foundIt = false;
	while ((e = e.parentNode) != null) {
		if (e == aardvark.selectedElem) {
			foundIt = true;
			break;
			}
		}
	if (foundIt) {
		aardvark.isOnAardvarkElem = false;
		return;
		}
	}
aardvark.isOnAardvarkElem = false;
aardvark.didWider = false;

if (elem == aardvark.selectedElem)
	return;
aardvark.widerStack = null;
aardvark.selectedElem = elem;
aardvark.showBoxAndLabel (elem, aardvark.makeElementLabelString (elem));
aardvark.innerItem = null;
aardvark.moved = false;
};

//-------------------------------------------------
aardvark.keyPress = function (evt) {
if (!evt)
	evt = aardvark.window.event;
var c;

if (evt.ctrlKey || evt.metaKey || evt.altKey)
  return true;

var keyCode = evt.keyCode ? evt.keyCode :
			evt.charCode ? evt.charCode :
			evt.which ? evt.which : 0;

c = String.fromCharCode(keyCode).toLowerCase();

var command = aardvark.commands[c];

if (command) {
	if (command.needsElement) {
		if (aardvark.selectedElem &&
				(command.func(aardvark.selectedElem) == true))
			aardvark.showKeybox (command);
		}
	else {
		if (command.func() == true)
			aardvark.showKeybox (command);
		}
	}

if (c < 'a' || c > 'z')
	return true;

if (evt.preventDefault)
	evt.preventDefault ();
else
	evt.returnValue = false;
return false;
};

//-------------------------------------------------
// this is the main entry point when starting aardvark
aardvark.start = function () {
aardvark.loadCommands();

if (aardvark.isBookmarklet) {
	aardvark.window = window;
	aardvark.doc = document;
	aardvark.showHelpTip(0);
	}
else {
	aardvark.doc = ((gContextMenu) ? gContextMenu.target.ownerDocument : window._content.document);
	aardvark.window = window._content;
	}

if (aardvark.doc.aardvarkRunning) {
	aardvark.quit();
	return;
	}
else {
	aardvark.makeElems ();
	aardvark.selectedElem = null;
	aardvark.doc.aardvarkRunning = true;

	if (aardvark.doc.all) {
		aardvark.doc.attachEvent ("onmouseover", aardvark.mouseOver);
		aardvark.doc.attachEvent ("onmousemove", aardvark.mouseMove);
		aardvark.doc.attachEvent ("onmouseup", aardvark.mouseUp);
		aardvark.doc.attachEvent ("onkeypress", aardvark.keyPress);
		}
	else {
		aardvark.doc.addEventListener ("mouseover", aardvark.mouseOver, false);
		aardvark.doc.addEventListener ("mouseup", aardvark.mouseUp, false);
		aardvark.doc.addEventListener ("mousemove", aardvark.mouseMove, false);
		aardvark.doc.addEventListener ("keypress", aardvark.keyPress, false);
		}

	if (!aardvark.isBookmarklet) {
		var t = new Date().getTime()/(1000*60);
		var diff = t - aardvark.tipLastShown;
		if (diff > 60) { // more than an hour
			aardvark.tipLastShown = Math.round(t);
			aardvark.prefManager.setIntPref("extensions.aardvark@rob.brown.tipLastShown",
				aardvark.tipLastShown);
			aardvark.showHelpTip(diff);
			}
		}s
	}
};

if (aardvark.isBookmarklet) {
	if (aardvark.userCallbacks) {
		for (var i = 0; i<aardvark.userCallbacks.length; i++)
			aardvark.userCallbacks[i]();
		}
	if (!aardvark.delayStart)
		setTimeout ("aardvark.start();", 100);
	aardvark.isLoaded = true;
	}
else {
	aardvark.prefManager =
		Components.classes["@mozilla.org/preferences-service;1"]
		.getService(Components.interfaces.nsIPrefBranch);
	aardvark.tipLastShown = aardvark.prefManager.getIntPref(
		"extensions.aardvark@rob.brown.tipLastShown");
	}
